/* Copyright(C) 2021. Huawei Technologies Co.,Ltd. All rights reserved.
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

// Package common this for util method
package common

import (
	"fmt"
	"math"
	"regexp"
	"strings"
)

var (
	reg910A = regexp.MustCompile(Pattern910A)
	reg910B = regexp.MustCompile(Pattern910B)
)

// IsGreaterThanOrEqualInt32 check num range
func IsGreaterThanOrEqualInt32(num int64) bool {
	if num >= int64(math.MaxInt32) {
		return true
	}

	return false
}

// IsValidUtilizationRate valid utilization rate is 0-100
func IsValidUtilizationRate(num uint32) bool {
	if num > uint32(Percent) || num < 0 {
		return false
	}

	return true
}

// IsValidChipInfo valid chip info is or not empty
func IsValidChipInfo(chip *ChipInfo) bool {
	return chip.Name != "" || chip.Type != "" || chip.Version != ""
}

// IsValidBoardInfo check whether the board info is valid
func IsValidBoardInfo(board *BoardInfo) bool {
	return board.BoardId != InvalidID || board.PcbId != InvalidID ||
		board.BomId != InvalidID || board.SlotId != InvalidID
}

// IsValidCardID valid card id
func IsValidCardID(cardID int32) bool {
	// for cardID, please watch the maximum value of the driver is changed in the future version
	return cardID >= 0 && cardID < HiAIMaxCardID
}

// IsValidDeviceID valid device id
func IsValidDeviceID(deviceID int32) bool {
	return deviceID >= 0 && deviceID < HiAIMaxDeviceNum
}

// IsValidLogicIDOrPhyID valid logic id
func IsValidLogicIDOrPhyID(id int32) bool {
	return id >= 0 && id < HiAIMaxCardNum*HiAIMaxDeviceNum
}

// IsValidCardIDAndDeviceID check two params both needs meet the requirement
func IsValidCardIDAndDeviceID(cardID, deviceID int32) bool {
	if !IsValidCardID(cardID) {
		return false
	}

	return IsValidDeviceID(deviceID)
}

// IsValidDevNumInCard valid devNum in card
func IsValidDevNumInCard(num int32) bool {
	return num > 0 && num <= HiAIMaxDeviceNum
}

// IsValidVDevID valid vir device id
func IsValidVDevID(vDevID uint32) bool {
	return vDevID >= MinVDevID && vDevID < MaxVDevID
}

// GetDeviceTypeByChipName get device type by chipName
func GetDeviceTypeByChipName(chipName string) string {
	if strings.Contains(chipName, "310P") {
		return Ascend310P
	}
	if strings.Contains(chipName, "310B") {
		return Ascend310B
	}
	if strings.Contains(chipName, "310") {
		return Ascend310
	}
	if reg910B.MatchString(chipName) {
		return Ascend910B
	}
	if reg910A.MatchString(chipName) {
		return Ascend910
	}
	return ""
}

func get910TemplateNameList() map[string]struct{} {
	return map[string]struct{}{"vir16": {}, "vir08": {}, "vir04": {}, "vir02": {}, "vir01": {}}
}

func get910BTemplateNameList() map[string]struct{} {
	return map[string]struct{}{
		"vir03_1c_8g": {}, "vir05_1c_8g": {}, "vir05_1c_16g": {},
		"vir06_1c_16g": {}, "vir10_3c_16g": {}, "vir10_3c_16g_nm": {},
		"vir10_3c_32g": {}, "vir10_4c_16g_m": {}, "vir12_3c_32g": {}}
}

func get310PTemplateNameList() map[string]struct{} {
	return map[string]struct{}{"vir04": {}, "vir02": {}, "vir01": {}, "vir04_3c": {}, "vir02_1c": {},
		"vir04_4c_dvpp": {}, "vir04_3c_ndvpp": {}}
}

// IsValidTemplateName check template name meet the requirement
func IsValidTemplateName(devType, templateName string) bool {
	isTemplateNameValid := false
	switch devType {
	case Ascend310P:
		_, isTemplateNameValid = get310PTemplateNameList()[templateName]
	case Ascend910:
		_, isTemplateNameValid = get910TemplateNameList()[templateName]
	case Ascend910B:
		_, isTemplateNameValid = get910BTemplateNameList()[templateName]
	default:
	}
	return isTemplateNameValid
}

// RemoveDuplicate remove duplicate device
func RemoveDuplicate(list *[]string) []string {
	listValueMap := make(map[string]string, len(*list))
	var rmDupValueList []string
	for _, value := range *list {
		listValueMap[value] = value
	}
	for _, value := range listValueMap {
		rmDupValueList = append(rmDupValueList, value)
	}
	return rmDupValueList
}

// GetNpuName get npu name eg: name-type-version
func GetNpuName(chipInfo *ChipInfo) string {
	if chipInfo == nil {
		return ""
	}
	if len(chipInfo.Name) == 0 && len(chipInfo.Type) == 0 && len(chipInfo.Version) == 0 {
		return ""
	}
	return fmt.Sprintf("%s-%s-%s", chipInfo.Name, chipInfo.Type, chipInfo.Version)
}

// SetExternalParams transmit npu-exporter's startup parameters
func SetExternalParams(profilingTime int) {
	ProfilingTime = profilingTime
}

// Is910BChip current chip is 910B or not
func Is910BChip(chipName string) bool {
	reg910B := regexp.MustCompile(Pattern910B)
	return reg910B.MatchString(chipName)
}

// DeepCopyChipInfo copy chip info deeply
func DeepCopyChipInfo(chipInfo *ChipInfo) *ChipInfo {
	if chipInfo == nil {
		return nil
	}

	return &ChipInfo{
		Type:    chipInfo.Type,
		Name:    chipInfo.Name,
		Version: chipInfo.Version,
	}
}

// DeepCopyBoardInfo copy board info deeply
func DeepCopyBoardInfo(boardInfo *BoardInfo) *BoardInfo {
	if boardInfo == nil {
		return nil
	}

	return &BoardInfo{
		BoardId: boardInfo.BoardId,
		PcbId:   boardInfo.PcbId,
		BomId:   boardInfo.BomId,
		SlotId:  boardInfo.SlotId,
	}
}

// DeepCopyVDevActivityInfo copy VDevActivityInfo deeply
func DeepCopyVDevActivityInfo(vDevActivityInfo *VDevActivityInfo) *VDevActivityInfo {
	if vDevActivityInfo == nil {
		return nil
	}

	return &VDevActivityInfo{
		VDevID:         vDevActivityInfo.VDevID,
		VDevAiCoreRate: vDevActivityInfo.VDevAiCoreRate,
		VDevTotalMem:   vDevActivityInfo.VDevTotalMem,
		VDevUsedMem:    vDevActivityInfo.VDevUsedMem,
		VDevAiCore:     vDevActivityInfo.VDevAiCore,
		IsVirtualDev:   vDevActivityInfo.IsVirtualDev,
	}
}

// DeepCopyPcieBwInfo copy PCIEBwStat deeply
func DeepCopyPcieBwInfo(pcieBwInfo *PCIEBwStat) *PCIEBwStat {
	if pcieBwInfo == nil {
		return nil
	}

	return &PCIEBwStat{
		PcieRxPBw:   pcieBwInfo.PcieRxPBw,
		PcieRxNPBw:  pcieBwInfo.PcieRxNPBw,
		PcieRxCPLBw: pcieBwInfo.PcieRxCPLBw,
		PcieTxPBw:   pcieBwInfo.PcieTxPBw,
		PcieTxNPBw:  pcieBwInfo.PcieTxNPBw,
		PcieTxCPLBw: pcieBwInfo.PcieTxCPLBw,
	}
}

// DeepCopyMemoryInfo copy MemoryInfo deeply
func DeepCopyMemoryInfo(memoryInfo *MemoryInfo) *MemoryInfo {
	if memoryInfo == nil {
		return nil
	}

	return &MemoryInfo{
		MemorySize:      memoryInfo.MemorySize,
		MemoryAvailable: memoryInfo.MemoryAvailable,
		Frequency:       memoryInfo.Frequency,
		Utilization:     memoryInfo.Utilization,
	}
}

// DeepCopyHbmInfo copy HbmInfo deeply
func DeepCopyHbmInfo(hbmInfo *HbmInfo) *HbmInfo {
	if hbmInfo == nil {
		return nil
	}

	return &HbmInfo{
		MemorySize:        hbmInfo.MemorySize,
		Frequency:         hbmInfo.Frequency,
		Usage:             hbmInfo.Usage,
		Temp:              hbmInfo.Temp,
		BandWidthUtilRate: hbmInfo.BandWidthUtilRate,
	}
}

// DeepCopyStatInfo copy StatInfo deeply
func DeepCopyStatInfo(statInfo *StatInfo) *StatInfo {
	if statInfo == nil {
		return nil
	}

	return &StatInfo{
		MacRxPauseNum:          statInfo.MacRxPauseNum,
		MacTxPauseNum:          statInfo.MacTxPauseNum,
		MacRxPfcPktNum:         statInfo.MacRxPfcPktNum,
		MacTxPfcPktNum:         statInfo.MacTxPfcPktNum,
		MacRxBadPktNum:         statInfo.MacRxBadPktNum,
		MacTxBadPktNum:         statInfo.MacTxBadPktNum,
		RoceRxAllPktNum:        statInfo.RoceRxAllPktNum,
		RoceTxAllPktNum:        statInfo.RoceTxAllPktNum,
		RoceRxErrPktNum:        statInfo.RoceRxErrPktNum,
		RoceTxErrPktNum:        statInfo.RoceTxErrPktNum,
		RoceRxCnpPktNum:        statInfo.RoceRxCnpPktNum,
		RoceTxCnpPktNum:        statInfo.RoceTxCnpPktNum,
		RoceNewPktRtyNum:       statInfo.RoceNewPktRtyNum,
		MacTxBadOctNum:         statInfo.MacTxBadOctNum,
		MacRxBadOctNum:         statInfo.MacRxBadOctNum,
		RoceUnexpectedAckNum:   statInfo.RoceUnexpectedAckNum,
		RoceOutOfOrderNum:      statInfo.RoceOutOfOrderNum,
		RoceVerificationErrNum: statInfo.RoceVerificationErrNum,
		RoceQpStatusErrNum:     statInfo.RoceQpStatusErrNum,
		RoceEcnDBNum:           statInfo.RoceEcnDBNum,
		MacRXFcsErrPktNum:      statInfo.MacRXFcsErrPktNum,
	}
}

// DeepCopyOpticalInfo copy OpticalInfo deeply
func DeepCopyOpticalInfo(opticalInfo *OpticalInfo) *OpticalInfo {
	if opticalInfo == nil {
		return nil
	}

	return &OpticalInfo{
		OpticalState:    opticalInfo.OpticalState,
		OpticalTxPower0: opticalInfo.OpticalTxPower0,
		OpticalTxPower1: opticalInfo.OpticalTxPower1,
		OpticalTxPower2: opticalInfo.OpticalTxPower2,
		OpticalTxPower3: opticalInfo.OpticalTxPower3,
		OpticalRxPower0: opticalInfo.OpticalRxPower0,
		OpticalRxPower1: opticalInfo.OpticalRxPower1,
		OpticalRxPower2: opticalInfo.OpticalRxPower2,
		OpticalRxPower3: opticalInfo.OpticalRxPower3,
		OpticalVcc:      opticalInfo.OpticalVcc,
		OpticalTemp:     opticalInfo.OpticalTemp,
	}
}

// DeepCopyLinkSpeedInfo copy LinkSpeedInfo deeply
func DeepCopyLinkSpeedInfo(linkSpeedInfo *LinkSpeedInfo) *LinkSpeedInfo {
	if linkSpeedInfo == nil {
		return nil
	}

	return &LinkSpeedInfo{
		Speed: linkSpeedInfo.Speed,
	}
}

// DeepCopyLinkStatInfo copy LinkStatInfo deeply
func DeepCopyLinkStatInfo(linkStatInfo *LinkStatInfo) *LinkStatInfo {
	if linkStatInfo == nil {
		return nil
	}

	return &LinkStatInfo{
		LinkUPNum: linkStatInfo.LinkUPNum,
	}
}

// DeepCopyBandwidthInfo copy BandwidthInfo deeply
func DeepCopyBandwidthInfo(bandwidthInfo *BandwidthInfo) *BandwidthInfo {
	if bandwidthInfo == nil {
		return nil
	}

	return &BandwidthInfo{
		TxValue: bandwidthInfo.TxValue,
		RxValue: bandwidthInfo.RxValue,
	}
}

// DeepCopyDevProcessInfo copy DevProcessInfo deeply
func DeepCopyDevProcessInfo(devProcessInfo *DevProcessInfo) *DevProcessInfo {
	if devProcessInfo == nil {
		return nil
	}

	devProcArray := make([]DevProcInfo, 0)
	for _, item := range devProcessInfo.DevProcArray {
		devProcArray = append(devProcArray, item)
	}
	return &DevProcessInfo{
		DevProcArray: devProcArray,
		ProcNum:      devProcessInfo.ProcNum,
	}
}

// DeepCopyECCInfo copy ECCInfo deeply
func DeepCopyECCInfo(eccInfo *ECCInfo) *ECCInfo {
	if eccInfo == nil {
		return nil
	}

	return &ECCInfo{
		EnableFlag:                eccInfo.EnableFlag,
		SingleBitErrorCnt:         eccInfo.SingleBitErrorCnt,
		DoubleBitErrorCnt:         eccInfo.DoubleBitErrorCnt,
		TotalSingleBitErrorCnt:    eccInfo.TotalSingleBitErrorCnt,
		TotalDoubleBitErrorCnt:    eccInfo.TotalDoubleBitErrorCnt,
		SingleBitIsolatedPagesCnt: eccInfo.SingleBitIsolatedPagesCnt,
		DoubleBitIsolatedPagesCnt: eccInfo.DoubleBitIsolatedPagesCnt,
	}
}
